package com.zy.ServletFilter;

//使用Filter对敏感词汇进行过滤，利用Java的动态代理增强ServletRequest对象的getParameter()方法
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;

@WebFilter("/*")
public class FilterDemo6 implements Filter
{
    private ArrayList<String> list_=new ArrayList<>();
    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
        try
        {
            //1、获取文件真实路径
            ServletContext servletContext = filterConfig.getServletContext();
            String realPath = servletContext.getRealPath("/WEB-INF/classes/SensitiveWorld.txt");
            //2、读取文件
            BufferedReader bufferedReader=new BufferedReader(new FileReader(realPath));
            //3、将文件的每一行添加到数组
            String line=null;
            while ((line=bufferedReader.readLine())!=null)
            {
                list_.add(line);
            }
            bufferedReader.close();
        } catch (FileNotFoundException e)
        {
            e.printStackTrace();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        System.out.println(list_);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
    {
        //动态代理：创建代理，增强getParameter()方法
        /*
           创建代理对象三个参数：
                真实对象和代理对象的类加载器，
                真实对象实现的接口
                匿名内部类InvocationHandler
           返回值为代理对象
         */
        ServletRequest servletRequest1=(ServletRequest) Proxy.newProxyInstance(servletRequest.getClass().getClassLoader(), servletRequest.getClass().getInterfaces(), new InvocationHandler() {
            //代理逻辑，代理对象调用的方法都会执行该方法
            /*
            三个参数：
               1、Object proxy：代理对象
               2、Method method：代理对象的调用的方法以参数传入并封装为Method对象。反射技术
               3、Object[] args：方法传递的参数列表
            */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
            {
                if(method.getName().equals("getParameter"))
                {
                    /*
                      增强返回值,将敏感词汇替换为****
                      如果增强参数，则参数修改后，则传递修改后的参数名，而不是args
                    */
                    //相当于使用真实对象调用servletRequest方法
                    String value =(String) method.invoke(servletRequest, args);
                    //对返回值进行增强
                    if(value!=null)
                    {
                        for (String i:list_)
                        {
                            if(value.contains(i))
                                value=value.replaceAll(i,"***");
                        }
                    }
                    //返回增强后的方法返回值,增强返回值
                    return value;
                }
                return method.invoke(servletRequest,args);
            }
        });
        //放行，传递被代理的对象servletRequest1
        filterChain.doFilter(servletRequest1,servletResponse);
    }
    @Override
    public void destroy()
    {

    }
}
